﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.IO;
using System.Xml;
using System.Xml.Schema;

namespace Devsoft.Utilities
{
	public class Serializer
	{
		private static bool isValid = true;

		public static bool ValidateSchema(string xmlSource, string schemaSource)
		{
			StringReader xmlSourceReader = new StringReader(xmlSource);
			XmlTextReader xmlTextReader = new XmlTextReader(xmlSourceReader);

			StringReader schemaSourceReader = new StringReader(schemaSource);
			XmlTextReader schemaTextReader = new XmlTextReader(schemaSourceReader);

			XmlValidatingReader xmlValidatingReader = new XmlValidatingReader(xmlTextReader);
			XmlSchemaCollection xmlSchemaCollection = new XmlSchemaCollection();
			xmlSchemaCollection.Add(null, schemaTextReader);

			xmlValidatingReader.Schemas.Add(xmlSchemaCollection);
			xmlValidatingReader.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);

			try
			{
				while (xmlValidatingReader.Read()) { }
			}
			catch
			{
				isValid = false;
			}
			xmlValidatingReader.Close();

			return isValid;
		}

		private static void ValidationCallBack(object sender, ValidationEventArgs e)
		{
			isValid = false;
		}

		public static string Serialize(object obj)
		{
			XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType());
			TextWriter textWriter = new Utf8StringWriter();

			xmlSerializer.Serialize(textWriter, obj);
			return textWriter.ToString();
		}

		public static object Deserialize(string xmlSource, Type type)
		{
			StringReader xmlSourceReader = new StringReader(xmlSource);
			XmlSerializer xmlSerializer = new XmlSerializer(type);
			return xmlSerializer.Deserialize(xmlSourceReader);
		}

		public static void Serialize(object obj, string targetPath)
		{
			string text = Serialize(obj);
			File.WriteAllText(targetPath, text, Encoding.UTF8);
		}

		public static object Deserialize(Type type, string sourceFilePath)
		{
			string xmlSource = File.ReadAllText(sourceFilePath, Encoding.UTF8);
			return Deserialize(xmlSource, type);
		}

		public static void WriteBinary(object obj, string targetPath)
		{
			FileStream fs = new FileStream(targetPath, FileMode.Create);

			System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter =
				new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

			try
			{
				formatter.Serialize(fs, obj);
			}
			catch (System.Runtime.Serialization.SerializationException e)
			{
				Console.WriteLine("Failed to serialize. Reason: " + e.Message);
				throw;
			}
			finally
			{
				fs.Close();
			}
		}

		public static object ReadBinary(string targetPath)
		{
			FileStream fs = new FileStream(targetPath, FileMode.Open);
			try
			{
				System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter =
					new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

				return formatter.Deserialize(fs);
			}
			catch (System.Runtime.Serialization.SerializationException e)
			{
				Console.WriteLine("Failed to deserialize. Reason: " + e.Message);
				return null;
			}
			finally
			{
				fs.Close();
			}
		}

		public static byte[] GetBytes(object obj)
		{
			MemoryStream stream = new MemoryStream();
			System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter =
				new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

			try
			{
				formatter.Serialize(stream, obj);
				return stream.GetBuffer();
			}
			catch (System.Runtime.Serialization.SerializationException e)
			{
				throw new Exception("Failed to serialize. Reason: " + e.Message);
			}
			finally
			{
				stream.Close();
				stream.Dispose();
			}
		}

		public static object GetOriginalObject(byte[] buffer)
		{
			try
			{
				MemoryStream stream = new MemoryStream(buffer);
				System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter =
					new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

				return formatter.Deserialize(stream);
			}
			catch (System.Runtime.Serialization.SerializationException e)
			{
				throw new Exception("Failed to deserialize. Reason: " + e.Message);
			}
		}
	}

	internal class Utf8StringWriter : StringWriter
	{
		public override Encoding Encoding
		{
			get { return Encoding.UTF8; }
		}
	}
}
